package com.fulu.game.bi.service.impl.play;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.fulu.game.bi.common.util.csv.CsvExportUtil;
import com.fulu.game.bi.common.util.csv.Mapper;
import com.fulu.game.bi.common.util.csv.Querier;
import com.fulu.game.bi.common.util.lang.StringUtils;
import com.fulu.game.bi.common.util.math.MathUtils;
import com.fulu.game.bi.entity.bo.channel.GameOneClickListBO;
import com.fulu.game.bi.entity.bo.channel.GamePathListBO;
import com.fulu.game.bi.entity.bo.channel.GamePriceListBO;
import com.fulu.game.bi.entity.bo.channel.GameRoomStatListBO;
import com.fulu.game.bi.entity.enums.DataTypeEnum;
import com.fulu.game.bi.entity.enums.QueryTypeStatusEnum;
import com.fulu.game.bi.entity.vo.play.GameOneClickListVO;
import com.fulu.game.bi.entity.vo.play.GameOneClickRealTimeVO;
import com.fulu.game.bi.entity.vo.play.GamePathStatVO;
import com.fulu.game.bi.entity.vo.play.GamePriceListVO;
import com.fulu.game.bi.entity.vo.play.GamePriceRealtimeVO;
import com.fulu.game.bi.entity.vo.play.GameRoomRealTimeStatVO;
import com.fulu.game.bi.entity.vo.play.GameRoomStatVO;
import com.fulu.game.bi.hbase.HBaseGamePlaySceneDAO;
import com.fulu.game.bi.redis.service.play.GamePlaySceneService;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class GamePlaySceneServiceImpl extends BasePlayService implements GamePlaySceneService {

    @Autowired
    private HBaseGamePlaySceneDAO hBaseGamePlaySceneDAO;

    @Override
    public List<GameRoomRealTimeStatVO> roomRealTime() {
        GameRoomRealTimeStatVO today = hBaseGamePlaySceneDAO.findByParameter(DateUtil.today());
        today = today == null ? new GameRoomRealTimeStatVO() : today;
        GameRoomRealTimeStatVO yesterday = hBaseGamePlaySceneDAO.findByParameter(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -1)));
        yesterday = yesterday == null ? new GameRoomRealTimeStatVO() : yesterday;
        GameRoomRealTimeStatVO theDayBeforeYesterday = hBaseGamePlaySceneDAO.findByParameter(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -2)));
        theDayBeforeYesterday = theDayBeforeYesterday == null ? new GameRoomRealTimeStatVO() : theDayBeforeYesterday;
        GameRoomRealTimeStatVO lastWeekYesterdaySameDay = hBaseGamePlaySceneDAO.findByParameter(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -8)));
        lastWeekYesterdaySameDay = lastWeekYesterdaySameDay == null ? new GameRoomRealTimeStatVO() : lastWeekYesterdaySameDay;
        List<GameRoomRealTimeStatVO> list = new ArrayList<>();
        yesterday.setDispathcSuccessNumDay(MathUtils.chainRatio(yesterday.getDispathcSuccessNum(), theDayBeforeYesterday.getDispathcSuccessNum()));
        yesterday.setDispathcSuccessNumWeek(MathUtils.chainRatio(yesterday.getDispathcSuccessNum(), lastWeekYesterdaySameDay.getDispathcSuccessNum()));
        yesterday.setOrderNumDay(MathUtils.chainRatio(yesterday.getOrderNum(), theDayBeforeYesterday.getOrderNum()));
        yesterday.setOrderNumWeek(MathUtils.chainRatio(yesterday.getOrderNum(), lastWeekYesterdaySameDay.getOrderNum()));
        yesterday.setOrderUserNumDay(MathUtils.chainRatio(yesterday.getOrderUserNum(), theDayBeforeYesterday.getOrderUserNum()));
        yesterday.setOrderUserNumWeek(MathUtils.chainRatio(yesterday.getOrderUserNum(), lastWeekYesterdaySameDay.getOrderUserNum()));
        yesterday.setTryVioceUserNumDay(MathUtils.chainRatio(yesterday.getTryVioceUserNum(), theDayBeforeYesterday.getTryVioceUserNum()));
        yesterday.setTryVioceUserNumWeek(MathUtils.chainRatio(yesterday.getTryVioceUserNum(), lastWeekYesterdaySameDay.getTryVioceUserNum()));
        list.add(today);
        list.add(yesterday);
        return list;
    }

    @Override
    public List<String> roomNo() {
        return hBaseGamePlaySceneDAO.roomNo();
    }


    @Override
    public List<String> path() {
        return hBaseGamePlaySceneDAO.path();
    }

    @Override
    public List<GameRoomStatVO> list(GameRoomStatListBO listBO) {
        listBO.setTableName(gamePlaySceneStat.get(listBO.getQueryType()));
        listBO.setPageNum((listBO.getPageNum() - 1) * listBO.getPageSize());
        listBO.setDateType(CollectionUtil.isEmpty(listBO.getRoomNos()) ? DataTypeEnum.ALL.getType() : DataTypeEnum.EACH.getType());
        List<GameRoomStatVO> list = hBaseGamePlaySceneDAO.list(listBO);
        return list.stream().map(map -> {
            map.setQueryType(listBO.getQueryType());
            map.setRoomNo(Objects.equals(listBO.getDateType(), DataTypeEnum.ALL.getType()) ? "/" : map.getRoomNo());
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public void export(GameRoomStatListBO bo) {
        String fileName = "陪玩场景-派单厅";
        LinkedHashMap<String, Mapper<GameRoomStatVO>> map = new LinkedHashMap<>();
        QueryTypeStatusEnum anEnum = QueryTypeStatusEnum.getEnum(bo.getQueryType());
        switch (anEnum) {
            case DAY:
                map.put("日期", v -> v.getStartDate());
                break;
            default:
                map.put("日期", v -> v.getStartDate() + "-" + v.getEndDate());
                break;
        }
        map.put("派单厅ID", v -> v.getRoomNo());
        map.put("曝光人数", v -> v.getExposureUserNum() + "");
        map.put("曝光次数", v -> v.getExposureNum() + "");
        map.put("进厅人数", v -> v.getEnterRoomUserNum() + "");
        map.put("进厅次数", v -> v.getEnterRoomNum() + "");
        map.put("CTR", v -> v.getCtr().toString());
        map.put("进厅陪练师", v -> v.getEnterRoomPlayeeNum() + "");
        map.put("试音人数", v -> v.getTryVioceUserNum() + "");
        map.put("试音次数", v -> v.getTryVioceNum() + "");
        map.put("派单次数", v -> v.getDispathcNum() + "");
        map.put("派单成功次数", v -> v.getDispathcSuccessNum() + "");
        map.put("重新派单次数", v -> v.getRetryDispathcNum() + "");
        map.put("弃单次数", v -> v.getDropOrderNum() + "");
        map.put("弃单率", v -> v.getDropOrderNumRatio().toString());
        map.put("消费总金额", v -> v.getConsumeMoneyAll().toString());
        map.put("下单人数", v -> v.getOrderUserNum() + "");
        map.put("下单次数", v -> v.getOrderNum() + "");
        map.put("CVR", v -> v.getCvr().toString());
        map.put("订单消费金额", v -> v.getOrderConsumeMoneyAll().toString());
        map.put("钻石消费人数", v -> v.getVirtualMoneyUserNum() + "");
        map.put("钻石消费次数", v -> v.getVirtualMoneyNum() + "");
        map.put("钻石消费金额", v -> v.getVirtualMoneyAll().toString());
        map.put("礼物魅力值", v -> v.getCharmMoneyAll().toString());
        map.put("退款人数", v -> v.getRefundUserNum() + "");
        map.put("退款次数", v -> v.getRefundNum() + "");
        map.put("退款率", v -> v.getRefundNumRatio().toString());
        map.put("平均派单时长", v -> v.getDispathcTimeAvg().toString());

        Querier querier = (num) -> {
            PageInfo pageInfo = new PageInfo(listExport(bo));
            pageInfo.setHasNextPage(false);
            return pageInfo;
        };
        CsvExportUtil.export(100, fileName, map, querier);
    }

    public List<GameRoomStatVO> listExport(GameRoomStatListBO listBO) {
        listBO.setTableName(gamePlaySceneStat.get(listBO.getQueryType()));
        listBO.setPageNum((listBO.getPageNum() - 1) * listBO.getPageSize());
        listBO.setDateType(DataTypeEnum.EACH.getType());
        List<GameRoomStatVO> list = hBaseGamePlaySceneDAO.list(listBO);
        return list.stream().map(map -> {
            map.setQueryType(listBO.getQueryType());
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public List<GamePathStatVO> pathList(GamePathListBO listBO) {
        listBO.setTableName(gamePathListStat.get(listBO.getQueryType()));
        listBO.setDataType(DataTypeEnum.EACH.getType());
        List<GamePathStatVO> eachList = hBaseGamePlaySceneDAO.pathList(listBO);
        listBO.setDataType(DataTypeEnum.ALL.getType());
        listBO.setPathName(null);
        List<GamePathStatVO> allList = hBaseGamePlaySceneDAO.pathList(listBO);
        Map<String, GamePathStatVO> allMap = allList.stream().collect(Collectors.toMap(GamePathStatVO::getStatDate, GamePathStatVO -> GamePathStatVO));//NOPMD
        List<GamePathStatVO> collect = eachList.stream().map(map -> {
            GamePathStatVO gamePathStatVO = Optional.ofNullable(allMap.get(map.getStatDate())).orElse(new GamePathStatVO());
            map.setQueryType(listBO.getQueryType());
            map.setOrderUserNum(Optional.ofNullable(map.getOrderUserNum()).orElse(0));
            map.setOrderUserNumRatio(MathUtils.ratio(map.getOrderUserNum(), gamePathStatVO.getOrderUserNum()));
            map.setOrderNumRatio(MathUtils.ratio(map.getOrderNum(), gamePathStatVO.getOrderNum()));
            map.setOrderMoneyAllRatio(MathUtils.ratio(map.getOrderMoneyAll(), gamePathStatVO.getOrderMoneyAll()));
            return map;
        }).collect(Collectors.toList());
        collect.sort(Comparator.comparing(GamePathStatVO::getStatDate).thenComparing(GamePathStatVO::getOrderUserNum).reversed());
        return collect;
    }

    @Override
    public void pathExport(GamePathListBO bo) {
        String fileName = "陪玩场景-路径";
        LinkedHashMap<String, Mapper<GamePathStatVO>> map = new LinkedHashMap<>();
        QueryTypeStatusEnum anEnum = QueryTypeStatusEnum.getEnum(bo.getQueryType());
        switch (anEnum) {
            case DAY:
                map.put("日期", v -> v.getStartDate());
                break;
            default:
                map.put("日期", v -> v.getStartDate() + "-" + v.getEndDate());
                break;
        }
        map.put("路径", v -> v.getPathName());
        map.put("下单人数", v -> v.getOrderUserNum() + "");
        map.put("下单人数比率", v -> v.getOrderUserNumRatio().toString());
        map.put("下单次数", v -> v.getOrderNum() + "");
        map.put("下单次数比率", v -> v.getOrderNumRatio().toString());
        map.put("下单金额", v -> v.getOrderMoneyAll().toString());
        map.put("下单金额比率", v -> v.getOrderMoneyAllRatio().toString());
        Querier querier = (num) -> {
            PageInfo pageInfo = new PageInfo(pathList(bo));
            pageInfo.setHasNextPage(false);
            return pageInfo;
        };
        CsvExportUtil.export(100, fileName, map, querier);
    }

    @Override
    public List<GameOneClickRealTimeVO> clickRealtime() {
        GameOneClickRealTimeVO today = hBaseGamePlaySceneDAO.clickRealtime(DateUtil.today());
        today = today == null ? new GameOneClickRealTimeVO() : today;
        GameOneClickRealTimeVO yesterday = hBaseGamePlaySceneDAO.clickRealtime(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -1)));
        yesterday = yesterday == null ? new GameOneClickRealTimeVO() : yesterday;
        GameOneClickRealTimeVO theDayBeforeYesterday = hBaseGamePlaySceneDAO.clickRealtime(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -2)));
        theDayBeforeYesterday = theDayBeforeYesterday == null ? new GameOneClickRealTimeVO() : theDayBeforeYesterday;
        GameOneClickRealTimeVO lastWeekYesterdaySameDay = hBaseGamePlaySceneDAO.clickRealtime(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -8)));
        lastWeekYesterdaySameDay = lastWeekYesterdaySameDay == null ? new GameOneClickRealTimeVO() : lastWeekYesterdaySameDay;
        List<GameOneClickRealTimeVO> list = new ArrayList<>();
        yesterday.setSendOrderUserNumDay(MathUtils.chainRatio(yesterday.getSendOrderUserNum(), theDayBeforeYesterday.getSendOrderUserNum()));
        yesterday.setSendOrderUserNumWeek(MathUtils.chainRatio(yesterday.getSendOrderUserNum(), lastWeekYesterdaySameDay.getSendOrderUserNum()));
        yesterday.setRobOrderUserNumDay(MathUtils.chainRatio(yesterday.getRobOrderUserNum(), theDayBeforeYesterday.getRobOrderUserNum()));
        yesterday.setRobOrderUserNumWeek(MathUtils.chainRatio(yesterday.getRobOrderUserNum(), lastWeekYesterdaySameDay.getRobOrderUserNum()));
        yesterday.setOrderUserNumDay(MathUtils.chainRatio(yesterday.getOrderUserNum(), theDayBeforeYesterday.getOrderUserNum()));
        yesterday.setOrderUserNumWeek(MathUtils.chainRatio(yesterday.getOrderUserNum(), lastWeekYesterdaySameDay.getOrderUserNum()));
        yesterday.setOrderNumDay(MathUtils.chainRatio(yesterday.getOrderNum(), theDayBeforeYesterday.getOrderNum()));
        yesterday.setOrderNumWeek(MathUtils.chainRatio(yesterday.getOrderNum(), lastWeekYesterdaySameDay.getOrderNum()));
        list.add(today);
        list.add(yesterday);
        return list;
    }

    @Override
    public List<GameOneClickListVO> clickList(GameOneClickListBO listBO) {
        listBO.setTableName(gameClickListStat.get(listBO.getQueryType()));
        listBO.setDataType(StringUtils.isBlank(listBO.getCategoryName()) ? DataTypeEnum.ALL.getType() : DataTypeEnum.EACH.getType());
        List<GameOneClickListVO> list = hBaseGamePlaySceneDAO.clickList(listBO);
        return list.stream().map(map -> {
            map.setCategoryName(StringUtils.isBlank(listBO.getCategoryName()) ? "/" : listBO.getCategoryName());
            map.setQueryType(listBO.getQueryType());
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public void clickExport(GameOneClickListBO bo) {
        String fileName = "陪玩场景-一键下单";
        LinkedHashMap<String, Mapper<GameOneClickListVO>> map = new LinkedHashMap<>();
        QueryTypeStatusEnum anEnum = QueryTypeStatusEnum.getEnum(bo.getQueryType());
        switch (anEnum) {
            case DAY:
                map.put("日期", v -> v.getStartDate());
                break;
            default:
                map.put("日期", v -> v.getStartDate() + "-" + v.getEndDate());
                break;
        }
        map.put("品类", v -> v.getCategoryName());
        map.put("进入人数", v -> v.getEnterUserNum() + "");
        map.put("进入次数", v -> v.getEnterNum() + "");
        map.put("发单人数", v -> v.getSendOrderUserNum() + "");
        map.put("发单次数", v -> v.getSendOrderNum() + "");
        map.put("下单人数", v -> v.getOrderUserNum() + "");
        map.put("下单次数", v -> v.getOrderNum() + "");
        map.put("新用户下单人数", v -> v.getOrderNewUserNum() + "");
        map.put("新用户下单次数", v -> v.getOrderNewNum() + "");
        map.put("下单金额", v -> v.getOrderMoneyAll().toString());
        map.put("抢单人数", v -> v.getRobOrderUserNum() + "");
        map.put("系统匹配下单人数", v -> v.getSystemMatchUserNum() + "");
        map.put("系统匹配下单次数", v -> v.getSystemMatchNum() + "");
        map.put("人工抢单下单人数", v -> v.getManualRobOrderUserNum() + "");
        map.put("人工抢单下单次数", v -> v.getManualRobOrderNum() + "");
        map.put("超时人数", v -> v.getTimeoutUserNum() + "");
        map.put("超时次数", v -> v.getTimeoutNum() + "");
        map.put("取消人数", v -> v.getCancelUserNum() + "");
        map.put("取消次数", v -> v.getCancelNum() + "");
        map.put("退款人数", v -> v.getRefundUserNum() + "");
        map.put("退款次数", v -> v.getRefundNum() + "");
        map.put("系统匹配总时长", v -> v.getMatchTimeAll().toString());
        Querier querier = (num) -> {
            PageInfo pageInfo = new PageInfo(clickList(bo));
            pageInfo.setHasNextPage(false);
            return pageInfo;
        };
        CsvExportUtil.export(100, fileName, map, querier);
    }

    @Override
    public List<String> click() {
        return hBaseGamePlaySceneDAO.click();
    }

    @Override
    public List<String> newPrice() {
        return hBaseGamePlaySceneDAO.newPrice();
    }

    @Override
    public List<GamePriceRealtimeVO> priceRealtime() {
        GamePriceRealtimeVO today = hBaseGamePlaySceneDAO.priceRealtime(DateUtil.today());
        today = today == null ? new GamePriceRealtimeVO() : today;
        GamePriceRealtimeVO yesterday = hBaseGamePlaySceneDAO.priceRealtime(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -1)));
        yesterday = yesterday == null ? new GamePriceRealtimeVO() : yesterday;
        GamePriceRealtimeVO theDayBeforeYesterday = hBaseGamePlaySceneDAO.priceRealtime(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -2)));
        theDayBeforeYesterday = theDayBeforeYesterday == null ? new GamePriceRealtimeVO() : theDayBeforeYesterday;
        GamePriceRealtimeVO lastWeekYesterdaySameDay = hBaseGamePlaySceneDAO.priceRealtime(DateUtil.formatDate(DateUtil.offsetDay(new Date(), -8)));
        lastWeekYesterdaySameDay = lastWeekYesterdaySameDay == null ? new GamePriceRealtimeVO() : lastWeekYesterdaySameDay;
        List<GamePriceRealtimeVO> list = new ArrayList<>();
        yesterday.setEnterUserNumDay(MathUtils.chainRatio(yesterday.getEnterUserNum(), theDayBeforeYesterday.getEnterUserNum()));
        yesterday.setEnterUserNumWeek(MathUtils.chainRatio(yesterday.getEnterUserNum(), lastWeekYesterdaySameDay.getEnterUserNum()));
        yesterday.setEnterNumDay(MathUtils.chainRatio(yesterday.getEnterNum(), theDayBeforeYesterday.getEnterNum()));
        yesterday.setEnterNumWeek(MathUtils.chainRatio(yesterday.getEnterNum(), lastWeekYesterdaySameDay.getEnterNum()));
        yesterday.setOrderUserNumDay(MathUtils.chainRatio(yesterday.getOrderUserNum(), theDayBeforeYesterday.getOrderUserNum()));
        yesterday.setOrderUserNumWeek(MathUtils.chainRatio(yesterday.getOrderUserNum(), lastWeekYesterdaySameDay.getOrderUserNum()));
        yesterday.setOrderNumDay(MathUtils.chainRatio(yesterday.getOrderNum(), theDayBeforeYesterday.getOrderNum()));
        yesterday.setOrderNumWeek(MathUtils.chainRatio(yesterday.getOrderNum(), lastWeekYesterdaySameDay.getOrderNum()));
        yesterday.setOpenUserNumDay(MathUtils.chainRatio(yesterday.getOpenUserNum(), theDayBeforeYesterday.getOpenUserNum()));
        yesterday.setOpenUserNumWeek(MathUtils.chainRatio(yesterday.getOpenUserNum(), lastWeekYesterdaySameDay.getOpenUserNum()));
        yesterday.setRobOrderMoneyAllDay(MathUtils.chainRatio(yesterday.getRobOrderMoneyAll(), theDayBeforeYesterday.getRobOrderMoneyAll()));
        yesterday.setRobOrderMoneyAllWeek(MathUtils.chainRatio(yesterday.getRobOrderMoneyAll(), lastWeekYesterdaySameDay.getRobOrderMoneyAll()));
        list.add(today);
        list.add(yesterday);
        return list;
    }

    @Override
    public List<GamePriceListVO> priceList(GamePriceListBO listBO) {
        listBO.setTableName(gamePriceListStat.get(listBO.getQueryType()));
        listBO.setDataType(StringUtils.isBlank(listBO.getCategoryName()) ? DataTypeEnum.ALL.getType() : DataTypeEnum.EACH.getType());
        List<GamePriceListVO> list = hBaseGamePlaySceneDAO.priceList(listBO);
        return list.stream().map(map -> {
            map.setCategoryName(StringUtils.isBlank(listBO.getCategoryName()) ? "/" : listBO.getCategoryName());
            map.setQueryType(listBO.getQueryType());
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public void priceExport(GamePriceListBO bo) {
        String fileName = "陪玩场景-新客价";
        LinkedHashMap<String, Mapper<GamePriceListVO>> map = new LinkedHashMap<>();
        QueryTypeStatusEnum anEnum = QueryTypeStatusEnum.getEnum(bo.getQueryType());
        switch (anEnum) {
            case DAY:
                map.put("日期", v -> v.getStartDate());
                break;
            default:
                map.put("日期", v -> v.getStartDate() + "-" + v.getEndDate());
                break;
        }
        map.put("品类名称", v -> v.getCategoryName());
        map.put("进入人数", v -> v.getEnterUserNum() + "");
        map.put("进入次数", v -> v.getEnterNum() + "");
        map.put("开启人数", v -> v.getOpenUserNum() + "");
        map.put("接单人数", v -> v.getOrderUserNum() + "");
        map.put("接单次数", v -> v.getOrderNum() + "");
        map.put("接单金额", v -> v.getRobOrderMoneyAll().toString());
        Querier querier = (num) -> {
            PageInfo pageInfo = new PageInfo(priceList(bo));
            pageInfo.setHasNextPage(false);
            return pageInfo;
        };
        CsvExportUtil.export(100, fileName, map, querier);
    }


}
